use calamine::{open_workbook, DataType, Reader, Xlsx};
use rust_xlsxwriter::{Workbook, XlsxError};
use std::{fs, path::Path, time::SystemTime};
use glob::glob;
use rayon::prelude::*;
use std::sync::Mutex;
use std::collections::HashMap;

#[unsafe(no_mangle)]
fn merge(folder_path:String) -> Result<u8,XlsxError> {
    let username:String = std::env::var_os("USERNAME").unwrap().into_string().unwrap();
    let output_file: String = format!("C:/Users/{}/Desktop/merged.xlsx",username);
    // 收集文件路径和创建时间
    let mut files: Vec<(std::path::PathBuf, SystemTime)> = glob(&format!("{}\\*.xlsx", folder_path))
        .expect("Failed to read glob pattern")
        .filter_map(|entry| entry.ok())
        .map(|path| {
            let created = fs::metadata(&path)
                .and_then(|m| m.created())
                .unwrap_or(SystemTime::UNIX_EPOCH);
            (path, created)
        })
        .collect();
    if files.is_empty() {
        //eprintln!("No Excel files found in directory: {}", folder_path);
        return Ok(0);
    }
    // 按文件创建时间排序
    files.sort_by(|(_, a_time), (_, b_time)| a_time.cmp(b_time));
    // 存储所有文件数据的内存缓存
    let file_data_cache: Mutex<HashMap<_, _>> = Mutex::new(HashMap::new());
    // 并行读取所有文件内容到内存
    files.par_iter().for_each(|(file_path, _)| {
        let path: &Path = Path::new(file_path);
        let file_name: String = path.file_stem()
            .and_then(|name| name.to_str())
            .unwrap_or("unknown")
            .to_string();
        // 尝试打开工作簿
        let mut wb: Xlsx<_> = match open_workbook(path) {
            Ok(wb) => wb,
            Err(e) => {
                eprintln!("Failed to open Excel file: {}: {}", path.display(), e);
                return;
            }
        };      
        // 读取工作表
        let range: calamine::Range<DataType> = match wb.worksheet_range_at(0) {
            Some(Ok(range)) => range,
            Some(Err(e)) => {
                eprintln!("Failed to read 'worksheet_range_at(0)' from {}: {}", path.display(), e);
                return;
            }
            None => {
                eprintln!("Sheet 'worksheet_range_at(0)' not found in file: {}", path.display());
                return;
            }
        }; 
        // 将数据转换为高效格式存储在内存中
        let mut rows: Vec<Vec<String>> = Vec::new();
        for row in range.rows() {
            let mut row_data = Vec::with_capacity(row.len() + 1); // +1 为文件名列
            for cell in row {
                row_data.push(match cell {
                    DataType::String(s) => s.to_string(),
                    DataType::Float(f) => f.to_string(),
                    DataType::Int(i) => i.to_string(),
                    DataType::Bool(b) => b.to_string(),
                    DataType::Empty => String::new(),
                    _ => String::new(),
                });
            }
            // 添加文件名到行末
            row_data.push(file_name.clone());
            rows.push(row_data);
        }
        // 存储到缓存
        let mut cache: std::sync::MutexGuard<'_, HashMap<std::path::PathBuf, Vec<Vec<String>>>> = file_data_cache.lock().unwrap();
        cache.insert(file_path.clone(), rows);
    });
    // 创建新工作簿
    let mut workbook: Workbook = Workbook::new();
    let worksheet: &mut rust_xlsxwriter::worksheet::Worksheet = workbook.add_worksheet();
    // 从缓存中提取数据并写入
    let mut current_row: u32 = 0;
    for (file_path, _) in files.iter() {
        let cache: std::sync::MutexGuard<'_, HashMap<std::path::PathBuf, Vec<Vec<String>>>> = file_data_cache.lock().unwrap();
        if let Some(rows) = cache.get(file_path) {
            for (row_idx, row_data) in rows.iter().enumerate() {
                for (col_idx, value) in row_data.iter().enumerate() {
                    worksheet.write_string(
                        current_row + row_idx as u32, 
                        col_idx as u16, 
                        value
                    )?;
                }
            }
            current_row += rows.len() as u32;
        }
    } 
    workbook.save(&output_file)?;
    //println!("Merged file saved to: {}", output_file);
    Ok(1)
}